///////////////////////////////////////////////////////////////////////////////////////////////////
//                                Process Manager												//
//////////////////////////////////////////////////////////////////////////////////////////////////
/*

Copyright (c) 2008 

Arif Ali Saiyed
http://arif-ali-saiyed.blogspot.com/

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/
///////////////////////////////////////////////////////////////////////////////////////////////////
//  Author :   1) Arif Ali Saiyed  arif[dot]ali[dot]syyed[at]gmail[dot]com   [Remove one y from Syed]
//  Date of Creation :  2008-Apr-08
//  
///////////////////////////////////////////////////////////////////////////////////////////////////
// Change Log Goes here...
// 2008-Apr-08 : Arif 
//			- Writing the first line of code setting  up the Hooks
//          - Added Menus Kill, Priority(with Children) ( Currently It's Adding menu multiple times) 
//          - Added Action for each menu other than About ( Kill works like charm ;)      
// 2008-May-10 : Arif 
//			- Added code to Get the handle of 'Priority' pop-up menu and remove Priority Poop up menu and Kill menu item.
//			- Fixed a problem , everytime a menu pops up and new set of menu us to get added  ... now first we check if menu already exist dont add it.
// 2008-Oct-25 : Arif 
//			- Made an failed Attempt for  OwnerDraw menus. Perhaps in next release we will have it...
//            eventough first attempt failed , leaving the dung here for later use ;o) 
///////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SystemHook.h"
#include "stdio.h"

// linker options can be embedded directly in .cpp code thus:
#if defined(_MSC_VER) && _MSC_VER >= 1200
#pragma comment(linker, "/OPT:NOWIN98" )
#endif

#pragma data_seg(".SHARDATA")

HWND		g_hwndMain = NULL;
HHOOK		g_hookShell = NULL;
HHOOK		g_hookMenu = NULL;
HINSTANCE	g_hInstance = NULL;

BOOL        bullu;

#pragma data_seg()
#pragma comment(linker, "/section:.SHARDATA,rws")


// extern "C" 
// {
static LRESULT CALLBACK pmShellProc(int nCode, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK pmMenuProc(int nCode, WPARAM wParam, LPARAM lParam);
int  pmTestInt=0;
/*}*/

// int DrawMymenuItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		//we come here when DLL is loaded for hte first time.
		g_hInstance = hModule;
		return TRUE;

	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif


__declspec(dllexport) BOOL StartProcessMgr(HWND hWnd)
{

	if(g_hwndMain != NULL)
		return FALSE;			// we already have a main window, so hooks must already be installed

	//::MessageBox(0,L"arif",L"ranu",0);
	// shell hook to add to context menu
	g_hookShell = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)pmShellProc, g_hInstance, 0);

	// menu hook to handle the menu message
	g_hookMenu = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)pmMenuProc, g_hInstance, 0);

	if ((g_hookShell != NULL) && (g_hookMenu != NULL))
	{
		g_hwndMain = hWnd;		// the main window will be whichever window called SetHook
								// ie our main dialog window

		return TRUE;			// both hooks were successfully installed
	}

	return FALSE;				// one or both of the hooks was not installed successfully

}


__declspec(dllexport) BOOL StopProcessMgr(HWND hWnd)
{
	if(hWnd != g_hwndMain || hWnd == NULL)
		return FALSE;
	
	//::MessageBox(0,L"shalini",L"munna",0);
	BOOL unhooked = UnhookWindowsHookEx(g_hookShell);
	if(!unhooked)
		return FALSE;			// did not successfully uninstall the shell hook

	unhooked = UnhookWindowsHookEx (g_hookMenu);
	if(!unhooked)
		return FALSE;			// did not successfully uninstall the menu hook

	g_hwndMain = NULL;			// successfully uninstalled both hooks therefore do not need
								// to liaise with main window any longer
	return unhooked;
}



// ShellProc - adds / removes the "All the menus we have added" entry from the system menu

static LRESULT CALLBACK pmShellProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode < 0)
	{
		return CallNextHookEx(g_hookShell, nCode, wParam, lParam);
	}

	CWPSTRUCT *wps = (CWPSTRUCT*)lParam;
	HWND hWnd = (HWND)(wps->hwnd);

	//SRF1-Begin :  This where We have to Keep removing our menu, 
	//we added last time, this section can be removed if we can have  a flag for each app
	//which would check if menu is added or not ... for that purpose we a variable 'pmTestIn'
	
	if (wps->message == WM_MENUSELECT)
	{
		if(wps->lParam == NULL && HIWORD(wps->wParam) == 0xFFFF)
		{
			// Uncomment this when you want only one Menu RemoveMenu (GetSystemMenu (hWnd, FALSE), IDM_PMACTION, MF_BYCOMMAND);
			HMENU hSystemMenu = GetSystemMenu (hWnd, FALSE);
			int subMenuCount = GetMenuItemCount(hSystemMenu);
			wchar_t mMenuItemName1[40], mMenuItemName2[40], mMenuItemName3[40];
			GetMenuString(hSystemMenu, (subMenuCount-1),mMenuItemName1,40,MF_BYPOSITION); // this should FindTarget
			GetMenuString(hSystemMenu, (subMenuCount-2),mMenuItemName2,40,MF_BYPOSITION); // this should Priority
			GetMenuString(hSystemMenu, (subMenuCount-3),mMenuItemName3,40,MF_BYPOSITION); // this should Kill
			
			int ret1 = wcscmp(mMenuItemName1,L"&FindTarget");
			int ret2 = wcscmp(mMenuItemName2,L"&Priority");
			int ret3 = wcscmp(mMenuItemName3,L"&Kill");

			if ((ret1==0) && (ret2==0) && (ret3==0))
			{
				RemoveMenu(hSystemMenu, (subMenuCount-1),MF_BYPOSITION);
				RemoveMenu(hSystemMenu, (subMenuCount-2),MF_BYPOSITION);
				RemoveMenu(hSystemMenu, (subMenuCount-3),MF_BYPOSITION);
				RemoveMenu(hSystemMenu, (subMenuCount-4),MF_BYPOSITION);
			}
	
		}
	}
	//SRF1-End :  This where We have to Keep removing our menu, we added last time

    // SRF2-Begin :  This where We have to Add our Menus 
	if(wps->message == WM_INITMENUPOPUP)
	{
		HMENU hMenu = (HMENU)wps->wParam;
		if ((IsMenu (hMenu) & (HIWORD(wps->lParam) == TRUE)))
		{

			// Uncomment this when you want only one Menu AppendMenu (GetSystemMenu (hWnd, FALSE), MF_BYPOSITION | MF_STRING, IDM_PMACTION, L"Priority");
			
			// Get the handle to System Menu
			HMENU hSystemMenu = GetSystemMenu (hWnd, FALSE);

			//Check if this menu already exist. 
			int subMenuCount = GetMenuItemCount(hSystemMenu);
			wchar_t mMenuItemName1[40], mMenuItemName2[40], mMenuItemName3[40];
			GetMenuString(hSystemMenu, (subMenuCount-1),mMenuItemName1,40,MF_BYPOSITION); // this should FindTarget
			GetMenuString(hSystemMenu, (subMenuCount-2),mMenuItemName2,40,MF_BYPOSITION); // this should Priority
			GetMenuString(hSystemMenu, (subMenuCount-3),mMenuItemName3,40,MF_BYPOSITION); // this should Kill
			
			int ret1 = wcscmp(mMenuItemName1,L"&FindTarget");
			int ret2 = wcscmp(mMenuItemName2,L"&Priority");
			int ret3 = wcscmp(mMenuItemName3,L"&Kill");


			if ((ret1==0) && (ret2==0) && (ret3==0))
			{
				return CallNextHookEx(g_hookShell, nCode, wParam, lParam);
			}
			
			DWORD cPriority = ::GetPriorityClass(::GetCurrentProcess());
			DWORD fDefault = MF_STRING, fSpecial = (MF_STRING | MF_CHECKED),
				  fHigh = fDefault,fANormal= fDefault,fBNormal= fDefault,fNormal= fDefault,FLow= fDefault;
				  
				                 
			if (cPriority == HIGH_PRIORITY_CLASS) 
				fHigh = fSpecial;
			else if (cPriority == ABOVE_NORMAL_PRIORITY_CLASS) 
				fANormal = fSpecial;
			else if (cPriority == NORMAL_PRIORITY_CLASS) 
				fNormal = fSpecial;
			else if (cPriority == BELOW_NORMAL_PRIORITY_CLASS) 
				fBNormal = fSpecial;
			else if (cPriority == IDLE_PRIORITY_CLASS) 
				FLow = fSpecial;
			
			HMENU hMenuPopup = CreateMenu();
  		    hMenuPopup = CreateMenu ();
			AppendMenu (hMenuPopup, fHigh, IDM_PMACTION_H,    L"&High");
			AppendMenu (hMenuPopup, fANormal, IDM_PMACTION_AN,   L"&Above Normal");
			AppendMenu (hMenuPopup, fNormal, IDM_PMACTION_N,    L"&Normal");
			AppendMenu (hMenuPopup, fBNormal, IDM_PMACTION_BN,   L"&Below Normal");
			AppendMenu (hMenuPopup, FLow, IDM_PMACTION_L,  L"&Low");
			//AppendMenu (hMenuPopup, MF_SEPARATOR, 0,       NULL);
			//Lets not add about menu here...becaue it's hard fo us to handle it ;) 
			//AppendMenu (hMenuPopup, MF_STRING, IDM_PMACTION_AB,  L"Abo&ut");

				// Add tick mark for the current priority
	

			AppendMenu (hSystemMenu, MF_SEPARATOR, 0,       NULL);
			AppendMenu (hSystemMenu,MF_STRING, IDM_PMACTION_K, L"&Kill");
		//	AppendMenu (hSystemMenu,MF_OWNERDRAW, IDM_PMACTION_K, L"&Kill");
			AppendMenu (hSystemMenu,MF_POPUP, (UINT)hMenuPopup, L"&Priority");
			AppendMenu (hSystemMenu,MF_STRING, IDM_PMACTION_FG, L"&FindTarget");

			MENUINFO mInfo;
			mInfo.cbSize = sizeof(MENUINFO); 
			mInfo.fMask = MIM_BACKGROUND | MIM_APPLYTOSUBMENUS; 
			mInfo.hbrBack = CreateSolidBrush(RGB(128,128,128));
			//SetMenuInfo((HMENU)hMenuPopup, &mInfo);


		}
	}
	// SRF2-End  :  This where We have to Add our Menus 

	if(wps->message == WM_MEASUREITEM )
	{
	 //FILE *fptr= fopen("c:\\arifpm.txt","w");
	 //fprintf(fptr,"\n WM_MEASUREITEM called from WNDPROC");
	 //fclose(fptr);
	}

	if(wps->message == WM_DRAWITEM )
	{
	 //FILE *fptr= fopen("c:\\arifpm2.txt","w");
	 //fprintf(fptr,"\n WM_DRAWITEM  called from WNDPROC");
	 //fclose(fptr);
	    
		//DrawMymenuItem((LPDRAWITEMSTRUCT) lParam);	

	}

	return CallNextHookEx(g_hookShell, nCode, wParam, lParam);
}

void FindTarget()
{
	wchar_t szPath[MAX_PATH], szFindPath[MAX_PATH + 10];
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind;
	
	GetModuleFileName( NULL, szPath, MAX_PATH );
	hFind = FindFirstFile(szPath, &FindFileData);
	if((hFind != INVALID_HANDLE_VALUE))
	{
		swprintf(szFindPath, L"%s, %s", L"/select", szPath);
		ShellExecute(NULL,L"open", L"explorer", szFindPath, NULL, SW_MAXIMIZE); 
		//ShellExecute(NULL, _T("open"), _T("Explorer"), _T("/select, C:\\1.txt"), NULL, SW_SHOW);
		FILE *fptr= fopen("c:\\arifpm2.txt","w");
		fwprintf(fptr,szFindPath);
		fclose(fptr);
	}
	FindClose(hFind);

	return;
}
static LRESULT CALLBACK pmMenuProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode < 0)
	{
		return CallNextHookEx(g_hookMenu, nCode, wParam, lParam);
	}

	MSG *msg = (MSG *)lParam;
    // SRF-Begin This where We have to write the action for each of Menu
	/* // Uncomment this when you want only one Menu 
	if ((msg->message == WM_SYSCOMMAND) && (LOWORD(msg->wParam) == IDM_PMACTION))
	{
		::SetPriorityClass(::GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS);
	}
	*/

	if ((msg->message == WM_SYSCOMMAND))

	{
		switch (LOWORD(msg->wParam))
		{
		
		case IDM_PMACTION_K :  // Kill this bloody process it must be hanging the system
							  {
								  ::TerminateProcess(::GetCurrentProcess(),UINT(-1)); 	
							  break;
							  }
		case IDM_PMACTION_H :  
							{
								::SetPriorityClass(::GetCurrentProcess(),HIGH_PRIORITY_CLASS);	
								break;
							}
		case IDM_PMACTION_AN : 
							{
								::SetPriorityClass(::GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS);   	
								break;
							}
		case IDM_PMACTION_N :  
							{
								::SetPriorityClass(::GetCurrentProcess(),NORMAL_PRIORITY_CLASS);
								  break;
							}
		case IDM_PMACTION_BN : 
							{
								 ::SetPriorityClass(::GetCurrentProcess(),BELOW_NORMAL_PRIORITY_CLASS);	
								  break;
							}
		case IDM_PMACTION_L :  
							{
								::SetPriorityClass(::GetCurrentProcess(),IDLE_PRIORITY_CLASS);	
								break;
							}
		case IDM_PMACTION_FG :
			{
				FindTarget();
				break;
			}
		}
	}

	// SRF-End This where We have to write the action for each of Menu
	return CallNextHookEx(g_hookMenu, nCode, wParam, lParam);
}

// int DrawMymenuItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
// {
// 
//     FILE *fptr= fopen("c:\\arifpm33.txt","w"); 
// 	HDC DC = lpDrawItemStruct->hDC;
//        
// 	fprintf(fptr,"\nlpDrawItemStruct->itemID = \"%d\"  - \"%d\" ",lpDrawItemStruct->itemID,100);
// 	SetBkColor(DC,RGB(255,128,0));
// 	if (lpDrawItemStruct->itemID == IDM_PMACTION_K) 	
//     {	
// 	   FILE *fptr= fopen("c:\\arifpm33.txt","w");
// 	   fprintf(fptr,"\n WM_DRAWITEM  called from WNDPROC");
//    	
//     }
// 	fclose(fptr);
//  return 0;
// }
